/***********************************************************
 * Author: 	Brandon McKune
 * E-Mail:	bmckune.cs@gmail.com
 * Date:	September 2, 2011
 * Class:	Advanced OS
 * Time:	1150 - 1325
 * Smstr:	Fall 2011
 */

#include "ClScheduler.h"

ClScheduler* ClScheduler::m_ptrClScheduler = NULL;

const uint16_t PROCESSOR_OFF = 0;
const uint16_t PROCESSOR_ON	= 1;

/**
 *
 */
ClScheduler* ClScheduler::getInstance(){
	if(m_ptrClScheduler == NULL){
		m_ptrClScheduler = new ClScheduler();
	}

	return m_ptrClScheduler;
}

/**
 *
 */
ClScheduler::ClScheduler(){
	this->m_ptrReadyQueue.clear();
	this->m_ptrRunningQueue.clear();
	this->m_ptrFinishedQueue.clear();
	this->m_ptrDbProcessorsRateArr = NULL;
	this->m_ptrMaxProcessorsRateArr = NULL;
	this->m_uint64NumProcessors = 0;
	this->m_dbEnergyConsumed = 0;
	this->m_dbAverageProcRate = 1;
	this->m_boolSchedulerSetup = false;
	this->m_enumSchedulerType = BASE;
}

/**
 *
 */
ClScheduler::~ClScheduler(){
	CleanUpVector(&this->m_ptrReadyQueue);

	if(!this->m_ptrRunningQueue.empty()){
		this->m_ptrRunningQueue.clear();
//		delete(this->m_ptrRunningQueue);
	}

	if(!this->m_ptrFinishedQueue.empty()){
		this->m_ptrFinishedQueue.clear();
//		delete(this->m_ptrFinishedQueue);
	}

	if(m_ptrClScheduler != NULL){
		delete(m_ptrClScheduler);
	}
}


/**
 * 	setupScheduler Overloaded Function:
 * 	Description:
 * 		This function sets the number of processors that will be used for
 * 		scheduling as well as the blanket processor rate in Hz.
 * 	Parameters:
 * 		uint64_t numProcs
 * 			The number of processors that will be used
 * 		uint64_t maxHz
 *			The blanket max hertz for all processors within the system.
 */
void ClScheduler::setupScheduler(uint64_t numProcs, uint64_t maxHz){

	if(this->m_boolSchedulerSetup){
		cerr << "Scheduler has already been setup.  Extraneous setupScheduler()" << endl;
		return;
	}

	if(numProcs == 0 || maxHz == 0){
		cerr << "Invalid parameter for "
				"setupScheduler(uint64_t numProcs, uint64_t maxHz)" << endl;
		exit(1);
	}

	this->m_uint64NumProcessors = numProcs;

	this->m_ptrMaxProcessorsRateArr = new uint64_t[numProcs];
	this->m_ptrDbProcessorsRateArr = new double[numProcs];

	for(uint32_t i = 0; i < numProcs; i++){
		this->m_ptrMaxProcessorsRateArr[i] = maxHz;
		this->m_ptrDbProcessorsRateArr[i] = 1;
	}

	this->m_boolSchedulerSetup = true;
}

/**
 * 	setupScheduler Overloaded Function:
 * 	Description:
 * 		This function allows for a finer tuning of each processors max
 * 		rate in Hz.  If you call this function, then you must also adjust
 * 		energy consumption accordingly.  Due to timing constraints, the
 * 		update energy function does not consider the use of this.
 * 	Parameters:
 * 		uint64_t numProcs
 * 			The number of processors that will be used
 * 		uint64_t *maxHz
 *			The max hertz array representing each array individually.
 */
void ClScheduler::setupScheduler(uint64_t numProcs, uint64_t *maxHz){

	if(this->m_boolSchedulerSetup){
		cerr << "Scheduler has already been setup.  Extraneous setupScheduler()" << endl;
		return;
	}

	if(numProcs == 0){
		cerr << "Invalid parameter for numProcs" << endl;
		exit(1);
	}

	for(uint32_t i = 0; i < numProcs; i++){
		if(maxHz[i] == 0){
			cerr << "Invalid parameter for maxHz" << endl;
			exit(1);
		}
	}

	this->m_uint64NumProcessors = numProcs;
	this->m_ptrMaxProcessorsRateArr = new uint64_t[numProcs];
	this->m_ptrDbProcessorsRateArr = new double[numProcs];

	for(uint32_t i; i < numProcs; i++){
		this->m_ptrMaxProcessorsRateArr[i] = maxHz[i];
		this->m_ptrDbProcessorsRateArr[i] = 1;
	}

	this->m_boolSchedulerSetup = true;
}

/**
 *
 */
void ClScheduler::runScheduler(EnumSchedulerType SchedulingType, vector<ClTask> *taskInterrupts){
	switch(SchedulingType){
	case BASE:
		this->runBaseScheduler(taskInterrupts);
		break;
	case INTERMEDIATE:
		this->runIntermediateScheduler(taskInterrupts);
		break;
	case FULL:
		this->runFullScheduler(taskInterrupts);
		break;
	default:
		cerr << "ClScheduler::runScheduler()-> Invalid EnumSchedulerType" << endl;
		break;
	}
}

/**
 * 	printReadyQueue Function:
 * 	Description:
 * 		This function prints the contents of the ready queue at the time
 * 		called.
 * 	Parameters:
 * 		N/A
 * 	Returns:
 * 		void
 */
void ClScheduler::printReadyQueue(){
	cout << "Printing Ready Queue Contents:" << endl;
	printQueue(&this->m_ptrReadyQueue);
}

/**
 * 	printRunningQueue Function:
 * 	Description:
 * 		This function prints the contents of the running queue at the time called.
 * 	Parameters:
 * 		N/A
 * 	Returns:
 * 		void
 */
void ClScheduler::printRunningQueue(){
	cout << "Printing Running Queue Contents:" << endl;
	printQueue(&this->m_ptrRunningQueue);
}

/**
 * 	printFinishedQueue Function:
 * 	Description:
 * 		This function prints the contents of the finished queue at the time called.
 * 	Parameters:
 * 		N/A
 * 	Returns:
 * 		void
 */
void ClScheduler::printFinishedQueue(){
	cout << "Printing Finished Queue Contents:" << endl;
	printQueue(&this->m_ptrFinishedQueue);
}

/**
 * 	hasTasksWaiting Function:
 * 	Description:
 * 		This function is used to check whether or not the system still
 * 		has tasks left over in the ready queue.  The system might ignore
 * 		all incoming interrupts in order to successfully clear the ready
 * 		queue and shut down.
 * 	Parameters:
 * 		N/A
 * 	Return:
 * 		bool
 * 			true = readyQueue is not empty
 * 			false = readQueue is empty
 */
bool ClScheduler::hasTasksWaiting(){
	if(this->m_ptrReadyQueue.size() == 0){
		return true;
	}

	return false;
}

/**
 * 	runBaseScheduler Function:
 * 	Description:
 * 		The runBaseScheduler function implements the base scheduling algorithm
 * 		described in the paper.  The basic steps are as follows:
 * 			1. process interrupts
 * 			2. Check if the ready queue is empty
 * 				2a. Check if the running queue is empty
 * 					-Update energy consumption for no-op run
 * 				2b. Run Scheduling Interval for tasks
 * 					-Update instruction counts
 * 			3. If ready queue is not empty
 * 				3a. Update the queues to get current EDF tasks
 * 					in the running queue
 * 				3b. Run Scheduling interval
 * 				3c. Update instruction counts
 * 			4. Update post schedule interval running queue
 * 			5. Record energy metrics
 * 	Parameters:
 * 		vector<ClTask> *ptrTaskInterrupts
 * 			The vector containing the interrupts that occured during the last
 * 			schedule interval.
 * 	Returns:
 * 		void
 */
void ClScheduler::runBaseScheduler(vector<ClTask> *taskInterrupts){
	processInterrupts(taskInterrupts);

	if(this->m_ptrReadyQueue.empty()){
		if(this->m_ptrRunningQueue.empty()){
			//Do nothing
		}
		//Else Running Queue needs to run a SI
		else{
			updateTaskInstructionCounter();
		}
	}
	//Ready Queue is not empty
	else{
		//Adjust the queue's according to deadline
		updateRunningQueuePreSched();
		updateTaskInstructionCounter();
	}

	//Check to see if any tasks have finished
	updateRunningQueuePostSched();
	//Processor utilization array initialized with all 1's
	updateEnergyConsumed();
}

/**
 * 	runIntermediateScheduler Function:
 * 	Description:
 * 		This function runs the intermediate schedule described in
 * 		the paper.  The basic steps are as follows:
 * 			1. Turn off all processors except p = 0
 * 			2. process interrupts
 * 			3. Check if the ready queue is empty
 * 				3a. Check if the running queue is empty
 * 					-Update energy consumption for no-op run
 * 				3b. Run Scheduling Interval for tasks
 * 					-Update instruction counts
 * 			4. If ready queue is not empty
 * 				4a. Update the queues to get current EDF tasks
 * 					in the running queue
 * 				4b. Turn on processors with corresponding tasks
 * 				4c. Run Scheduling interval
 * 				4d. Update instruction counts
 * 			5. Update post schedule interval running queue
 * 			6. Record energy metrics
 * 	Parameters:
 * 		vector<ClTask> *ptrTaskInterrupts
 * 			The vector containing the interrupts that occured during the last
 * 			schedule interval.
 * 	Returns:
 * 		void
 */
void ClScheduler::runIntermediateScheduler(vector<ClTask> *taskInterrupts){
	updateActiveProcessorsPreschedule();
	processInterrupts(taskInterrupts);
	if(this->m_ptrReadyQueue.empty()){
		if(this->m_ptrRunningQueue.empty()){
			//Do nothing
		}
		//Else Running Queue needs to run a SI
		else{
			//turns on processors based on Running Queue
			updateActiveProcessorsRuntime();
			updateTaskInstructionCounter();
		}
	}
	//Ready Queue is not empty
	else{
		//Adjust the queue's according to deadline
		updateRunningQueuePreSched();
		//turns on processors based on Running Queue
		updateActiveProcessorsRuntime();
		updateTaskInstructionCounter();
	}

	//Check to see if any tasks have finished
	updateRunningQueuePostSched();
	//Processor utilization array initialized with all 1's
	updateEnergyConsumed();
}

/**
 * 	runFullScheduler Function:
 * 	Description:
 * 		This function runs the full schedule described in
 * 		the paper.  The basic steps are as follows:
 * 			1. Turn off all processors except p = 0
 * 			2. process interrupts
 * 			3. Check if the ready queue is empty
 * 				3a. Check if the running queue is empty
 * 					-Update energy consumption for no-op run
 * 				3b. Run Scheduling Interval for tasks
 * 					-Update instruction counts
 * 			4. If ready queue is not empty
 * 				4a. Update the queues to get current EDF tasks
 * 					in the running queue
 * 				4b. Turn on processors with corresponding tasks
 * 				4c. Adjust processor speed based on metrics
 * 				4d. Run Scheduling interval
 * 				4e. Update instruction counts
 * 			5. Update post schedule interval running queue
 * 			6. Record energy metrics
 * 	Parameters:
 * 		vector<ClTask> *ptrTaskInterrupts
 * 			The vector containing the interrupts that occured during the last
 * 			schedule interval.
 * 	Returns:
 * 		void
 */
void ClScheduler::runFullScheduler(vector<ClTask> *taskInterrupts){
	updateActiveProcessorsPreschedule();
	processInterrupts(taskInterrupts);
	if(this->m_ptrReadyQueue.empty()){
		if(this->m_ptrRunningQueue.empty()){
			//Do nothing
		}
		//Else Running Queue needs to run a SI
		else{
			//turns on processors based on Running Queue
			updateActiveProcessorsRuntime();
			updateTaskInstructionCounter();
		}
	}
	//Ready Queue is not empty
	else{
		//Adjust the queue's according to deadline
		updateRunningQueuePreSched();
		//turns on processors based on Running Queue
		updateActiveProcessorsRuntime();
		//Update the processor rate array based on metrics
		updateActiveProcessorRates();
		updateTaskInstructionCounter();
	}

	updateRunningQueuePostSched();
	//Processor utilization array initialized with all 1's
	updateEnergyConsumed();
}

/**
 * processInterrupts Function:
 * Description:
 * 		This function receives the vector of interrupts (tasks) that have arrived
 * 		at random in this real-time system.  This function sorts the arrived tasks
 * 		into the ready queue according to the following:
 * 			- Earliest Deadline First
 * 				-if Deadline is the same -> Least number of instructions
 * 					if num instructions are the same -> earliest arrival time
 * Parameters:
 * 		vector<ClTask*> *taskInterrupts
 * 			A vector containing the tasks to be processed.  If the pointer to
 * 			the vector is null, it is assumed that no tasks arrived during this
 * 			process interval and successfully exits the function.
 * Return:
 * 		void - N/A
 */
void ClScheduler::processInterrupts(vector<ClTask> *taskInterrupts){
	//No interrupts
	if(taskInterrupts == NULL){
		return;
	}
	std::vector<ClTask>::iterator iterTask = taskInterrupts->begin();
	//Loop through all the taskInterrupt vector
	while(iterTask != taskInterrupts->end()){
		this->insertToReadyQueue(*iterTask);
		iterTask++;
	}
	taskInterrupts->clear();
}

/**
 * 	updateProcessorUtilizationArray Function:
 * 	Description:
 * 		This function implements the FUNCTION(2) & (3) from the paper.  This function
 * 		should be called after the processInterrupt routine.  If not, this function
 * 		will process the frequency rates of each processor based on the current
 * 		tasks in the ready queue.
 * 	Parameters:
 * 		N/A
 * 	Return:
 * 		void
 */
void ClScheduler::updateProcessorUtilizationArray(){
	ClTask temp_ptr;

	//Loop through the RunningQueue and adjust each processor based on
	//information from the task
	for(uint32_t i = 0; i < this->m_uint64NumProcessors; i++){
		temp_ptr = this->m_ptrRunningQueue.at(i);

		//Temp holder for the task slack time
		double slackTime = this->m_ptrRunningQueue.at(i).getSlackTime();

		//If slack time is less than one, we have overhead
		if(slackTime < 1){
			this->m_ptrDbProcessorsRateArr[i] =
					slackTime + (1 - slackTime)*this->m_dbAverageProcRate;
		}
		//We do not have overhead, we need to get done ASAP
		else{
			this->m_ptrDbProcessorsRateArr[i] = 1;
		}
	}
}

/**
 * 	updateRunningPreQueue Function:
 * 	Description:
 * 		This function checks the ready queue to see if any tasks
 * 		waiting to run have an earlier deadline than any task in the running
 * 		queue.  Then adjusts the queue accordingly.
 * 	Parameters:
 * 		N/A
 * 	Return:
 * 		void
 */
void ClScheduler::updateRunningQueuePreSched(){
	vector<ClTask>::iterator rdyIter = this->m_ptrReadyQueue.begin();
	ClTask taskHolder;
	bool stillUpdating = true;
	bool wasInserted = false;

	//Just to verify there is something to check
	if(this->m_ptrReadyQueue.empty()){
		//Do nothing
		return;
	}

	while(stillUpdating && rdyIter != this->m_ptrReadyQueue.end()){

		//Make a copy of the task to be inserted
		taskHolder = *rdyIter;

		//Attempt to insert the task into the running queue
		wasInserted = this->insertToRunningQueue(taskHolder);

		//If the item was not inserted into the running queue
		//Stop looping through the readyQueue
		if(!wasInserted){
			stillUpdating = false;
		}
		//task inserted, remove from teh ready queue and reassign the
		//pointer
		else{
			//Remove the task from the ready queue
			this->m_ptrReadyQueue.erase(rdyIter);
			rdyIter = this->m_ptrReadyQueue.begin();
		}
	}
}

/**
 * 	insertToReadyQueue Function:
 * 	Description:
 * 		This function controls the insertion into the ready queue.
 * 	Parameters:
 * 		ClTask task
 * 			A copy of the task to be inserted into the ready queue
 * 			from the iterrupt routine
 * 	Return:
 * 		void
 */
bool ClScheduler::insertToReadyQueue(ClTask task){
	this->insertTask(&this->m_ptrReadyQueue, task);
	return true;
}

/**
 * 	insertToRunningQueue Function:
 * 	Description:
 * 		This function inserts a task into the running queue at
 * 		the appropriate slot based on EDF.  If the running queue
 * 		has g_numProcessors tasks, then the function checks to
 * 		see if the element being passed should be in the running
 * 		queue and sorts accordingly.  This function then calls
 * 		inserToReadyQueue(ClTask) for any non-fitting tasks.
 * 	Parameters:
 *		ClTask task
 *			The task to be inserted into the running queue
 *	Returns:
 *		bool
 *			Whether or not the task was inserted
 */
bool ClScheduler::insertToRunningQueue(ClTask task){
	bool wasInserted = false;

	//Special case to running queue only where we cannot compare
	//any characteristic of the task with an item in the running
	//queue, but we just don't want to insert and allow insertTask
	//to handle.
	if(this->m_ptrRunningQueue.size() == 0){
		insertTask(&this->m_ptrRunningQueue, task);
		return true;
	}

	//Check to see if the queue is full
	if(this->m_ptrRunningQueue.size() < g_numProcessors){
		//insert task into running queue because the queue
		//is not full
		insertTask(&this->m_ptrRunningQueue, task);
		return true;
	}

	vector<ClTask>::iterator runIter = this->m_ptrRunningQueue.end();
	runIter--;
	ClTask taskHolder;

	//Check to see if the task's deadline  is greater than the last
	//element in the running queue
	if(task.getAbsoluteDeadline() > runIter->getAbsoluteDeadline()){
		//insert nothing into running queue
		this->insertToReadyQueue(task);
	}
	//The task's deadline is equal to the last item in the running queue.
	else if(task.getAbsoluteDeadline() == runIter->getAbsoluteDeadline()){
		//The task's instruction count is the same
		//Compare to see which task arrived first
		if(task.getArrivalTime() < runIter->getArrivalTime()){
			taskHolder = *runIter;
			insertToReadyQueue(taskHolder);
			this->m_ptrRunningQueue.erase(runIter);
			insertTask(&this->m_ptrRunningQueue, task);
			wasInserted = true;
		}
	}
	//The task's deadline is less than the last item in the running queue.
	else{
		taskHolder = *runIter;
		insertToReadyQueue(taskHolder);
		this->m_ptrRunningQueue.erase(runIter);
		insertTask(&this->m_ptrRunningQueue, task);
		wasInserted = true;
	}

	return wasInserted;
}

/**
 * 	insertTask Function:
 * 	Description:
 * 		This function attempts to insert the task into the given queue
 * 		in order based on deadline, number of instructions, and arrival
 * 		time of the task.
 * 	Parameters:
 * 		ClTask taskToInsert
 * 			The task to insert into the queue
 * 	Return:
 * 		void
 */
void ClScheduler::insertTask(vector<ClTask> *queue, ClTask task){
	//Check to make sure the pointer passed isn't null
	if(queue == NULL){
		cerr << "ClScheduler::insertTask queue parameters is NULL." << endl;
		exit(1);
	}

	//If nothing is in the queue, then we do not need to check for
	//order of elements within the queue.
	if(queue->size() == 0){
		queue->push_back(task);
		return;
	}

	vector<ClTask>::iterator queueIter = queue->begin();

	//Loop until we get to the end or the task has been inserted
	while(queueIter != queue->end()){
		//If the task deadline is less than the task in the ready queue
		if(task.getAbsoluteDeadline() < queueIter->getAbsoluteDeadline()){
			queue->insert(queueIter,task);
			return;
		}
		//Task deadlines are the same
		else if(task.getAbsoluteDeadline() == queueIter->getAbsoluteDeadline()){

			//Check to see if the task has less instructions than the task in
			//the ready queue.
			if(task.getNumInstructions() < queueIter->getNumInstructions()){
				queue->insert(queueIter, task);
				return;
			}
			//the instruction count is the same
			else if(task.getNumInstructions() == queueIter->getNumInstructions()){

				//Compare to see which task arrived first
				if(task.getArrivalTime() < queueIter->getArrivalTime()){
					queue->insert(queueIter, task);
					return;
				}
			}
		}
		//Move to the next task in the queue because the task must
		//go after the current task in the queue or stillSorting is false
		queueIter++;
	}

	//If I reach the end of the queue then push the task to the
	//last element.
	queue->push_back(task);
}

/**
 * 	updateRunningPostQueue Function:
 * 	Description:
 * 		This function looks into the running queue and checks to see if
 * 		any running tasks have finished executing.  Removes that task
 * 		from the running queue and re-adjusts the running queue in EDF
 * 		order.
 * 	Parameters:
 * 		N/A
 * 	Return:
 * 		void
 */
void ClScheduler::updateRunningQueuePostSched(){
	vector<ClTask>::iterator tempIter = this->m_ptrRunningQueue.begin();

	//Loop through all the tasks within the running queue.  If the Running
	//Queue is empty, then exit successfully
	while(tempIter != this->m_ptrRunningQueue.end()){
		int64_t tempInstructs, tempInstructsCompleted;
		tempInstructs = tempIter->getNumInstructions();
		tempInstructsCompleted = tempIter->getNumInstructionsCompleted();

		//Check to see if all instructions have been completed
		if((tempInstructs - tempInstructsCompleted) <= 0){
			//Add the finished task to the finished queue
			this->m_ptrFinishedQueue.push_back(*tempIter);

			//erase returns the next element after the erased element
			tempIter = this->m_ptrRunningQueue.erase(tempIter);
		}
		//Task has not finished executing
		else{
			tempIter++;
		}
	}
}

/**
 *	updateAverageProcRate Function:
 *	Description:
 *		This function is used in the full scheduling algorithm in order
 *		to determine the processing rate of each processor during execution.
 *	Parameters:
 *		N/A
 *	Return:
 *		void
 */
void ClScheduler::updateAverageProcRate(){
	for(uint32_t i = 0; i < this->m_uint64NumProcessors; i++){
		this->m_dbAverageProcRate += this->m_ptrDbProcessorsRateArr[i];
	}

	this->m_dbAverageProcRate = this->m_dbAverageProcRate
				/ (this->m_uint64NumProcessors + 1);
}

/**
 * 	updateEnergyConsumed Function:
 * 	Description:
 * 		The update energy consumed function adds the processor rate
 * 		to the energy consumed variable.  If the processor ran at 100%
 * 		then we add 1.  Since our algorithm used the same max processing
 * 		rates for all processors, this can be used.  If you mix rates,
 * 		this algorithm must be changed to adjust based on a base rate.
 * 	Parameters:
 * 		N/A
 * 	Return:
 * 		void
 */
void ClScheduler::updateEnergyConsumed(){
	for(uint32_t i = 0; i < this->m_uint64NumProcessors; i++){
		this->m_dbEnergyConsumed += this->m_ptrDbProcessorsRateArr[i];
	}
}

/**
 * 	updateTaskInstructionCounter Function:
 * 	Description:
 * 		This function updates each instruction counter within the task
 * 		object.  This should be ran after a scheduling interval has
 * 		occured.
 * 	Parameters:
 * 		N/A
 * 	Return:
 * 		void
 */
void ClScheduler::updateTaskInstructionCounter(){
	int32_t index = 0;
	vector<ClTask>::iterator tempIter = this->m_ptrRunningQueue.begin();

	while(tempIter != this->m_ptrRunningQueue.end()){
		uint64_t instructsPerSec =
			this->m_ptrDbProcessorsRateArr[index]*this->m_ptrMaxProcessorsRateArr[index];
		uint64_t numInstructionsRan = instructsPerSec / g_Intervalusec;

		tempIter->incrementCompletedInstructions(numInstructionsRan);
		tempIter++;
		index++;
	}
}

/**
 * 	printQueue Function:
 * 	Description:
 * 		This function is a private function that encapsulates the print
 * 		code for any vector object.
 * 	Parameters:
 * 		vector<ClTask> *ptr
 * 			The pointer to the vector object to print.
 * 	Return:
 * 		void
 */
void ClScheduler::printQueue(vector<ClTask> *queue){
	vector<ClTask>::iterator iter = queue->begin();

	while(iter != queue->end()){
		iter->printTaskInternals();
		iter++;
	}
}

/**
 * 	updateActiveProcessorsPreschedule Function:
 * 	Description:
 * 		This function turns the power off on all processors within the
 * 		processor utilization array except for processor 0.
 * 	Parameters:
 * 		N/A
 * 	Return:
 * 		void
 */
void ClScheduler::updateActiveProcessorsPreschedule(){
	uint64_t index;

	for(index = 1; index < g_numProcessors; index++){
		this->m_ptrDbProcessorsRateArr[index] = PROCESSOR_OFF;
	}
}

/**
 * 	updateActiveProcessorsRuntime Function:
 * 	Description:
 * 		This function turns the power to each processor according to
 * 		the number of active tasks within the running queue.
 * 	Parameters:
 * 		N/A
 * 	Return:
 * 		void
 */
void ClScheduler::updateActiveProcessorsRuntime(){
	uint64_t numTaskQueued = this->m_ptrRunningQueue.size();

	uint64_t index;

	for(index = 1; index < numTaskQueued; index++){
		this->m_ptrDbProcessorsRateArr[index] = PROCESSOR_ON;
	}
}

/**
 * 	updateActiveProcessorRates Function:
 * 	Description:
 * '	This function updates the each individual processor rate
 * 		prior to running a scheduling interval.  It takes into account
 * 		the specific tasks slack time, deadline, and arrival time.
 * 	Parameters:
 * 		N/A
 * 	Return:
 * 		void
 */
void ClScheduler::updateActiveProcessorRates(){
	uint64_t index = 0;
	double temp_dbSlackTime = 0;
	bool temp_boolHasIdleProcessors = false;
	ClTask temp_ClTask;
	double temp_dbFreqRate = 0;

	//Check to see if there are idle processors for this run
	if((g_numProcessors - this->m_ptrRunningQueue.size()) > 1){
		temp_boolHasIdleProcessors = true;
	}else{
		temp_boolHasIdleProcessors = false;
	}

	//Loop through each processor rate and adjust
	//according to the equations 2', 3', 4'
	for(index = 0; index < g_numProcessors; index++){
		temp_ClTask = this->m_ptrRunningQueue.at(index);
		//Compute the slack time
		temp_dbSlackTime = temp_ClTask.getSlackTime();
		//Cannot adjust processor speed because the task
		//can just meet the deadline or will miss the deadline
		//at the fastest rate
		if(temp_dbSlackTime >= 1){
			temp_dbFreqRate = 1;
		}
		//There is slack time available
		else{
			//If there are idle processors, then equation 2'
			if(temp_boolHasIdleProcessors){
				double temp_compTime = temp_ClTask.getComputationalTime();
				double temp_deadline = temp_ClTask.getAbsoluteDeadline();
				double temp_arrivalTime = temp_ClTask.getArrivalTime();
				temp_dbFreqRate = temp_compTime / (temp_deadline - temp_arrivalTime);
			}
			//There are not idle processors, equation 4'
			else{
				temp_dbFreqRate = temp_dbSlackTime + (1 - temp_dbSlackTime) *
						this->m_dbAverageProcRate;
			}
		}

		this->m_ptrDbProcessorsRateArr[index] = temp_dbFreqRate;
	}
}
